<?php

namespace Modules\Core\Entities;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
// use Illuminate\Database\Eloquent\Relations;
use Modules\User\Entities\User;

use ThrowException;

class BaseEntity extends Model
{
    // use SoftDeletes;
    static public $resourceName = '资源';
    protected $dates = ['deleted_at'];

    protected $currentPage = 1;
    protected $perPage = 100;
    protected $itemTotal = 0;
    protected $only = false;
    public $builder = null;
    public $list = false;


    // 是否展示
    public function scopeListed($query)
    {
        return $query->where('is_listed', 1);
    }

    public function scopeOnStock($query)
    {
        return $query->where('status', 1);
    }

    public function scopeOffStock($query)
    {
        return $query->where('status', 0);
    }

    public function scopeUserPhone($query, $phone)
    {
        $user = User::where('phone', $phone)->first();

        return $query->where('user_id', @$user->id ?: 0);
    }

    public  function scopeBelongUser($query, $user)
    {
        return $query->where('user_id', $user->id);
    }

    // 搜索
    public function scopeSearch($query, $key)
    {
        return $query->where('title', 'like', '%' . $key . '%');
    }

    // 按id筛选并排序
    public function scopeIds($query, $ids)
    {
        $ids = $ids ?: [];
        return $query->whereIn('id', $ids)->orderByRaw("FIELD(id, " . implode(", ", $ids) . ")");
    }

    public function getNodeTypeTextAttribute()
    {
        $map = config('map.node_type_text');

        return @$map[$this->node_type];
    }

    public function getActivityTypeTextAttribute()
    {
        $map = config('map.activity_type_text');

        return @v($map[$this->activity_type], '');
    }

    // 所属node
    public function node()
    {
        $class = config('map.node_type')[$this->node_type];
        return $this->belongsTo($class, 'node_id');
    }

    // 所属活动
    public function activity()
    {
        $class = config('map.node_type')[$this->activity_type];
        return $this->belongsTo($class, 'activity_id');
    }

    // 获取营销活动
    public function getActivity()
    {
        if (!$this->activity_type) {
            return null;
        }

        return $this->activity;
    }

    // 获取营销活动
    static public function getNode($nodeType, $where)
    {
        $class = config('map.node_type')[$nodeType];

        return $class::getEntity($where);
    }

    //
    public function getArray($filter = null)
    {
        $builder = $this->builder ?: $this;
        $list = $this->list->toArray();
        // 屏蔽字段
        if ($this->only)
            $list = arrayFilter($list, ['*' => $this->only]);

        if ($filter) 
            $list = arrayFilter($list, ['*' => $filter]);

        return $list;
    }

    //
    public function getInfo($filter = [])
    {
        return arrayFilter($this->toArray(), $filter);
    }

    public function initList()
    {
        $builder = $this->builder ?: $this;

        $this->itemTotal = $builder->count();

        $this->list = $this->list ?: $builder->skip(($this->currentPage - 1) * $this->perPage)->take($this->perPage)->orderBy($this->table . '.id', 'desc')->get();
    }

    // 是否处于下架状态
    public function isOffStock()
    {
        return $this->status == 0;
    }

    // 是否处于上架状态
    public function isOnStock()
    {
        return $this->status == 1;
    }

    public function pluck($field)
    {
        return $this->list->pluck($field);
    }

    public function generateListResponse()
    {
        $builder = $this->builder ?: $this;

        $perPage = $this->perPage ?: 10;
    	$pageTotal = ceil($this->itemTotal / $perPage);
    	
        $list = $this->list->toArray();
        // 屏蔽字段
        if ($this->only) {
            $list = arrayFilter($list, ['*' => $this->only]);
        } 

    	return [
    		'list' => $list,
    		'current_page' => $this->currentPage,
    		'item_total' => $this->itemTotal,
    		'min_id' => $this->min_id ? $this->min_id : 0,
    		'kong_xiang' => $this->leitai_kongche ? $this->leitai_kongche : 0,
    		'page_total' => $pageTotal,
    		'play_type' => isset($list[0]) && isset($list[0]['play_type']) ? $list[0]['play_type'] : 0
    	];
    }

    public function each($fun)
    {
        $this->list = $this->list->each(function ($item, $key) use($fun) {
            $fun($item, $key);
        });
    }

    static public function getEntity(Array $options, $throwException = true)
    {
    	$class = get_called_class();

        $where = array_except($options, ['has', 'with', 'with_count', 'builder']);

        if (@$options['builder']) {
            $entity = $options['builder']->where($where);
        }
        else {
            $entity = $class::where($where);
        }

        if (@v($options['has']))
            $entity = $entity->has($options['has']);

        if (@v($options['with']))
            $entity = $entity->with($options['with']);

        if (@v($options['with_count']))
            $entity = $entity->withCount($options['with_count']);

        $entity = $entity->first();

    	$entity || ($throwException && ThrowException::NotFound($class::$resourceName.'不存在'));

    	return $entity;
    }

    static public function getList($options = [], $shouldInit = true)
    {
    	$class = get_called_class();
    	$item = new $class();

        $options = $class::beforeGetList($options);

        if (@$options['category_id']) {
            $options['scopes']['category'] = $options['category_id'];
        }

        if (isset($options['sort'])) {
            if ($options['sort'] == 'price_desc')
                $options['order_by'] = ['money_price' => 'desc'];
            elseif ($options['sort'] == 'price_asc')
                $options['order_by'] = ['money_price' => 'asc'];
            elseif ($options['sort'] == 'time_desc')
                $options['order_by'] = ['created_at' => 'desc'];
            elseif ($options['sort'] == 'time_asc')
                $options['order_by'] = ['created_at' => 'asc'];
            elseif ($options['sort'] == 'sale_desc')
                $options['order_by'] = ['sales' => 'desc'];
            elseif ($options['sort'] == 'sale_desc')
                $options['order_by'] = ['sales' => 'asc'];
        }

    	$item->currentPage = intVal(@v($options['page'], $item->currentPage));
        $item->perPage = intVal(@v($options['per_page'], $item->perPage));

        $item->only = @v($options['only']);

        $item->builder = @v($options['builder'], $item->newQuery());

    

        // if (isset($options['sort_by'])) {
        //     $item->builder->sortBy($options['sort_by']);
        // }

        if (isset($options['key'])) {
            $options['scopes'] = @v($options['scopes'], []);
            $options['scopes']['search'] = $options['key'];
        }

        if (isset($options['left_join'])) {
            $item->builder->leftJoin($options['left_join'][0], $options['left_join'][1], $options['left_join'][2], $options['left_join'][3]);
        }

        if (isset($options['inner_join'])) {
            $item->builder->join($options['inner_join'][0], $options['inner_join'][1], $options['inner_join'][2], $options['inner_join'][3]);
        }

    	if (isset($options['where'])) {
    		$item->builder->where($options['where']);
    	}

        if (@$options['created_start_at']) {
            $time = $options['created_start_at'];
            if (strlen($time) === 10) {
                $time .= ' 00:00:00';
            }
            $item->builder->where('created_at', '>', $time);
        }

        if (@$options['created_end_at']) {
            $time = $options['created_end_at'];
            if (strlen($time) === 10) {
                $time .= ' 23:59:59';
            }
            $item->builder->where('created_at', '<', $time);
        }

        if (isset($options['with'])) {
            $item->builder->with($options['with']);
        }

        if (isset($options['with_count'])) {
            $item->builder->withCount($options['with_count']);
        }

        if (isset($options['user_phone'])) {
            $options['scopes']['userPhone'] = $options['user_phone'];
        }

        if (isset($options['scopes'])) {
            foreach ($options['scopes'] as $key => $scope) {
                if (is_integer($key)) {
                    $item->builder->$scope();
                }
                else {
                    $item->builder->$key($scope);
                }
            }
        }

        if (isset($options['where_has'])) {
            if (is_array($options['where_has']))
                $item->builder->whereHas($options['where_has'][0], $options['where_has'][1]);
            else 
                $item->builder->whereHas($options['where_has']);
        }


        if (isset($options['has'])) {
            foreach ($options['has'] as $has) {
                $item->builder->has($has);
            }
        }

        if (isset($options['advanced_where'])) {
            if (is_array($options['advanced_where'])) {
                foreach ($options['advanced_where'] as $where) {
                    $item->builder->where($where);
                }
            } else {
                $item->builder->where($options['advanced_where']);
            }
        }

        // \Log::error($options);
        if (@$options['ids']) {
            
            if (!is_array($options['ids']))
                $options['ids'] = json_decode($options['ids'], true);


            if (@count($options['ids']) > 0)
                $item->builder->whereIn('id', $options['ids'])->orderByRaw("FIELD(id, " . implode(", ", $options['ids']) . ")");
        }


        if (isset($options['order_by'])) {
            foreach ($options['order_by'] as $key => $value) {
                $item->builder->orderBy($key, $value);
            }
        }
        

        if (isset($options['where_in'])) {
            foreach ($options['where_in'] as $key => $in) {
                $item->builder->whereIn($key, $in);
            }
        }

        if (isset($options['where_not_in'])) {
            foreach ($options['where_not_in'] as $key => $in) {
                $item->builder->whereNotIn($key, $in);
            }
        }

        if (isset($options['where_null'])) {
            foreach ($options['where_null'] as $v) {
                $item->builder->whereNull($v);
            }
        }


        $shouldInit && $item->initList();

    	return $item; 
    }


    // 获取builder
    static public function getBuilder($options)
    {
        // \Log::error(self::getList($options, false)->builder->toSql());
        return self::getList($options, false)->builder;
    }

    static public function beforeGetList($options)
    {
        return $options;
    }

    static public function beforeCreated($info)
    {
        return $info;
    }

    static public function create($info) 
    {
        $class = get_called_class();

        $info = $class::beforeCreated($info);

        try{
            $info['uuid'] = @v($info['uuid'], uniqid());
            $item = new $class($info);
            $item->save();
        }
        catch (\Illuminate\Database\QueryException $e) {
            \Log::error($e->getMessage());
            ThrowException::Conflict('保存失败，请检查是否填写完整及格式是否正确');
        }

        return $item;
    }

    static public function existOrCreate($where, $info = null) 
    {
        $class = get_called_class();

        return $class::isExisting($where) ?: $class::create($info ?: $where) ;
    }

    static public function isExisting($where)
    {
        $class = get_called_class();

        return $class::where($where)->first();
    }

    // 增加访问量
    public function addVisit($total)
    {
        $this->update([
            'visit_total' => $this->visit_total + $total
        ]);
    }

    public function show()
    {
        $this->is_listed = 1;
        $this->save();
    }

    public function hide()
    {
        $this->is_listed = 0;
        $this->save();
    }

    // 更新options字段
    public function setOptions($updateOptions)
    {
        $options = $this->options ?: [];

        $options = array_merge($options, $updateOptions);

        $this->update([
            'options' => $options
        ]);
    }
}

